package com.yunwushanhe.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yunwushanhe.bean.req.ArticleAddReq;
import com.yunwushanhe.bean.req.ArticlePageReq;
import com.yunwushanhe.bean.req.ArticleUpdateReq;
import com.yunwushanhe.bean.ret.ResponseResult;
import com.yunwushanhe.bean.vo.*;
import com.yunwushanhe.constant.Constant;
import com.yunwushanhe.constant.RedisConstant;
import com.yunwushanhe.entity.ArticleTag;
import com.yunwushanhe.entity.Category;
import com.yunwushanhe.entity.RoleMenu;
import com.yunwushanhe.mapper.ArticleMapper;
import com.yunwushanhe.entity.Article;
import com.yunwushanhe.mapper.ArticleTagMapper;
import com.yunwushanhe.mapper.CategoryMapper;
import com.yunwushanhe.service.ArticleService;
import com.yunwushanhe.service.ArticleTagService;
import com.yunwushanhe.util.BeanCopyUtil;
import com.yunwushanhe.util.RedisCache;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 文章表(Article)表服务实现类
 *
 * @author makejava
 * @since 2023-08-04 12:38:08
 */
@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements ArticleService {
    @Resource
    private ArticleMapper articleMapper;
    @Resource
    private CategoryMapper categoryMapper;
    @Resource
    private RedisCache redisCache;
    @Resource
    private ArticleTagService articleTagService;

    @Override
    public ResponseResult<List<ArticleHotVO>> hotArticleList() {
        LambdaQueryWrapper<Article> qw = new LambdaQueryWrapper<>();
        qw.eq(Article::getStatus, Constant.ARTICLE_STATUS_NORMAL);
        qw.orderByDesc(Article::getViewCount);
        Page<Article> articlePage = new Page<>(Constant.HOT_PAGE_NUM, Constant.HOT_PAGE_SIZE);
        page(articlePage,qw);
        List<Article> articles = articlePage.getRecords();

        articles = articles.stream()
                .map(article -> {
                    // 直接从redis中获取viewCount
                    Integer viewCount = redisCache.getCacheMapValue(RedisConstant.ARTICLE_VIEWCOUNT_KEY, article.getId().toString());
                    return article.setViewCount(viewCount.longValue());
                })
                .collect(Collectors.toList());

        List<ArticleHotVO> articleHotVOS = BeanCopyUtil.copyBeanList(articles, ArticleHotVO.class);
        return ResponseResult.ok(articleHotVOS);
    }

    @Override
    public ResponseResult<PageVO<List<ArticleVO>>> articleList(Integer pageNum,Integer pageSize,Long categoryId) {
        LambdaQueryWrapper<Article> qw = new LambdaQueryWrapper<>();
        qw.eq(categoryId > 0,Article::getCategoryId,categoryId);
        qw.eq(Article::getStatus,Constant.ARTICLE_STATUS_NORMAL);
        qw.orderByDesc(Article::getIsTop);
        Page<Article> articlePage = new Page<>(pageNum,pageSize);
        page(articlePage,qw);

        List<Article> articles = articlePage.getRecords();


        articles = articles.stream()
                .map(article -> {

                    // 直接从redis中获取viewCount
                    Integer viewCount = redisCache.getCacheMapValue(RedisConstant.ARTICLE_VIEWCOUNT_KEY, article.getId().toString());
                    article.setViewCount(viewCount.longValue());

                    return article.setCategoryName(categoryMapper.selectById(article.getCategoryId()).getName());
                })
                .collect(Collectors.toList());

        List<ArticleVO> articleVOS = BeanCopyUtil.copyBeanList(articles, ArticleVO.class);
        PageVO<List<ArticleVO>> pageVO = new PageVO<>(articleVOS,articlePage.getTotal());
        return ResponseResult.ok(pageVO);
    }

    @Override
    public ResponseResult<ArticleDetailVO> getArticleDetail(Long id) {
        Article article = articleMapper.selectById(id);

        // 直接从redis中获取viewCount
        Integer viewCount = redisCache.getCacheMapValue(RedisConstant.ARTICLE_VIEWCOUNT_KEY, id.toString());
        article.setViewCount(viewCount.longValue());

        Category category = categoryMapper.selectById(article.getCategoryId());
        article.setCategoryName(category.getName());
        ArticleDetailVO articleDetailVO = BeanCopyUtil.copyBean(article, ArticleDetailVO.class);
        return ResponseResult.ok(articleDetailVO);
    }

    @Override
    public ResponseResult<Object> updateViewCount(Long id) {
        redisCache.autoincrementCatchMapValue(RedisConstant.ARTICLE_VIEWCOUNT_KEY,id.toString(),RedisConstant.ARTICLE_VIEWCOUNT_INCREMENT_SIZE);
        return ResponseResult.ok();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult<Object> addArticle(ArticleAddReq articleAddReq) {
        Article article = BeanCopyUtil.copyBean(articleAddReq, Article.class);
        save(article);
        // save方法不但做了插入,还将插入后的id返回复制给了插入的对象

        Long articleId = article.getId();
        List<ArticleTag> articleTagList = articleAddReq.getTags().stream()
                .map(tagId -> new ArticleTag(articleId,tagId))
                .collect(Collectors.toList());

        articleTagService.saveBatch(articleTagList);
        return ResponseResult.ok();
    }

    @Override
    public ResponseResult<PageVO<List<ArticleAdminPageVO>>> listAllArticle(ArticlePageReq articlePageReq) {
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.hasText(articlePageReq.getTitle()),Article::getTitle,articlePageReq.getTitle());
        queryWrapper.like(StringUtils.hasText(articlePageReq.getSummary()),Article::getSummary,articlePageReq.getSummary());

        Page<Article> articlePage = new Page<>(articlePageReq.getPageNum(), articlePageReq.getPageSize());
        page(articlePage,queryWrapper);

        List<ArticleAdminPageVO> articleAdminPageVOS = BeanCopyUtil.copyBeanList(articlePage.getRecords(), ArticleAdminPageVO.class);

        return ResponseResult.ok(new PageVO<>(articleAdminPageVOS,articlePage.getTotal()));
    }

    @Override
    public ResponseResult<ArticleUpdateVO> getArticleById(Long id) {
        Article article = getById(id);
        LambdaQueryWrapper<ArticleTag> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ArticleTag::getArticleId,id);
        List<ArticleTag> articleTagList = articleTagService.list(queryWrapper);
        ArticleUpdateVO articleUpdateVO = BeanCopyUtil.copyBean(article, ArticleUpdateVO.class);

        articleUpdateVO.setTags(new ArrayList<>()); // 这行代码不加上去，就会报错，出现空指针异常

        for (ArticleTag articleTag : articleTagList) {
            articleUpdateVO.getTags().add(articleTag.getTagId());
        }
        return ResponseResult.ok(articleUpdateVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult<Object> updateArticleById(ArticleUpdateReq articleUpdateReq) {
        Article article = BeanCopyUtil.copyBean(articleUpdateReq, Article.class);
        updateById(article);

        LambdaQueryWrapper<ArticleTag> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ArticleTag::getArticleId,articleUpdateReq.getId());
        articleTagService.remove(queryWrapper);

        List<ArticleTag> articleTagList = articleUpdateReq.getTags().stream()
                .map(tagId -> new ArticleTag(articleUpdateReq.getId(),tagId))
                .collect(Collectors.toList());

        articleTagService.saveBatch(articleTagList);
        return ResponseResult.ok();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult<Object> deleteArticleById(String id) {
        String[] arrayId = id.split(",");
        ArrayList<Long> listId = new ArrayList<>();
        for (String s : arrayId) {
            listId.add(Long.valueOf(s));
        }
        removeByIds(listId);

        // 把关系表中的关系一并删除了
        LambdaQueryWrapper<ArticleTag> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(ArticleTag::getArticleId,listId);
        articleTagService.remove(queryWrapper);

        return ResponseResult.ok();
    }
}

